package com.qqq.adminservice.user.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.qqq.adminservice.config.service.ISysDictionaryService;
import com.qqq.adminservice.user.domain.dto.SysUserDTO;
import com.qqq.adminservice.user.domain.dto.SysUserListReqDTO;
import com.qqq.adminservice.user.domain.dto.SysUserLoginDTO;
import com.qqq.adminservice.user.domain.entity.SysUser;
import com.qqq.adminservice.user.domain.vo.SysUserLoginVO;
import com.qqq.adminservice.user.mapper.SysUserMapper;
import com.qqq.adminservice.user.service.ISysUserService;
import com.qqq.commoncore.utils.AESUtil;
import com.qqq.commoncore.utils.VerifyUtil;
import com.qqq.commondomain.domain.ResultCode;
import com.qqq.commondomain.domain.dto.LoginUserDTO;
import com.qqq.adminservice.user.domain.dto.PasswordLoginDTO;
import com.qqq.commondomain.domain.dto.TokenDTO;
import com.qqq.commondomain.exception.ServiceException;
import com.qqq.commonsecurity.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * B端用户登录服务实现类
 */
@Slf4j
@Service
public class SysUserServiceImpl implements ISysUserService {

    /**
     * token服务类
     */
    @Autowired
    private TokenService tokenService;

    /**
     * B端用户表mapper
     */
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 字典服务引用
     */
    @Autowired
    private ISysDictionaryService sysDictionaryService;

    @Override
    public TokenDTO login(PasswordLoginDTO passwordLoginDTO) {
        // LoginUserDTO 结构为了维护登录用户⽣命周期
        // 因此登录完成会设置用户信息、token、⽣命周期等属性
        LoginUserDTO loginUserDTO = new LoginUserDTO();
        // 1、校验手机号:是否合理
        if (!VerifyUtil.checkPhone(passwordLoginDTO.getPhone())) {
            throw new ServiceException("手机号不合理", ResultCode.INVALID_PARA.getCode());
        }
        // 判断手机号是否存在于mysql
        SysUser sysUser = sysUserMapper.selectByPhoneNumber(
                AESUtil.encryptHex(passwordLoginDTO.getPhone()));
        if (null == sysUser) {
            throw new ServiceException("手机号不存在",
                    ResultCode.INVALID_PARA.getCode());
        }

        // 2、校验密码
        // 先解密，再加密（aes）：为了不让其明文传输。需要前后端约定密钥
        //aes是对称加密，可逆，一旦秘钥泄露，所有密码都可被破解
        String password = AESUtil.decryptHex(passwordLoginDTO.getPassword());
        if (StringUtils.isEmpty(password)) {
            throw new ServiceException("密码解析为空", ResultCode.INVALID_PARA.getCode());
        }
        //不可逆加密，即使是系统管理员也无法知道用户密码
        String passwordEncrypt = DigestUtil.sha256Hex(password);
        // 拿加密后的密码与数据库字段比较
        if (!passwordEncrypt.equals(sysUser.getPassword())) {
            throw new ServiceException("密码错误", ResultCode.INVALID_PARA.getCode());
        }
        // 3、校验用户状态
        if (sysUser.getStatus().equals("disable")) {
            throw new ServiceException(ResultCode.USER_DISABLE);
        }
        // 4、设置登录信息
        loginUserDTO.setUserId(sysUser.getId());
        loginUserDTO.setUserName(sysUser.getNickName());
        loginUserDTO.setUserFrom("sys");
        // 该方法会设置用户token、⽣命周期，并返回 Token
        return tokenService.createToken(loginUserDTO);
    }

    /**
     * 新增或修改用户信息
     * 修改只能修改昵称、备注、状态，其他参数传了也不改，保证业务
     * 修改时，需带上昵称、备注、状态。逻辑为直接覆盖原有数据
     *
     * @param sysUserDTO
     * @return
     */
    @Override
    public Long addOrEditUser(SysUserDTO sysUserDTO) {
        SysUser sysUser = new SysUser();
        if (null == sysUserDTO.getUserId()) {
            // 新增用户
            if (StringUtils.isEmpty(sysUserDTO.getPassword()) || !sysUserDTO.checkPassword()) {
                throw new ServiceException("密码为空或校验失败", ResultCode.INVALID_PARA.getCode());
            }
            if (!VerifyUtil.checkPhone(sysUserDTO.getPhoneNumber())) {
                throw new ServiceException("手机号格式错误", ResultCode.INVALID_PARA.getCode());
            }
            // 唯一性校验
            SysUser existSysUser = sysUserMapper.selectByPhoneNumber(
                    AESUtil.encryptHex(sysUserDTO.getPhoneNumber()));
            if (null != existSysUser) {
                throw new ServiceException("手机号已注册", ResultCode.INVALID_PARA.getCode());
            }
            // 判断身份信息
            if (StringUtils.isEmpty(sysUserDTO.getIdentity()) || null ==
                    sysDictionaryService.selectDictDataByDataKey(sysUserDTO.getIdentity())) {
                throw new ServiceException("用户身份错误", ResultCode.INVALID_PARA.getCode());
            }
            // 新增用户才设置，修改用户传了也不改，保证业务
            sysUser.setPassword(DigestUtil.sha256Hex(sysUserDTO.getPassword()));
            sysUser.setPhoneNumber(AESUtil.encryptHex(sysUserDTO.getPhoneNumber()));
            sysUser.setIdentity(sysUserDTO.getIdentity());
        }
        sysUser.setId(sysUserDTO.getUserId());
        sysUser.setNickName(sysUserDTO.getNickName());
        if (null == sysDictionaryService.selectDictDataByDataKey(sysUserDTO.getStatus())) {
            // 要改，但是传错了
            throw new ServiceException("用户状态传参错误", ResultCode.INVALID_PARA.getCode());
        }
        sysUser.setStatus(sysUserDTO.getStatus());
        sysUser.setRemark(sysUserDTO.getRemark());
        sysUserMapper.insertOrUpdate(sysUser);
        // 踢⼈
        if (null != sysUserDTO.getUserId()
                && "disable".equalsIgnoreCase(sysUserDTO.getStatus())) {
            tokenService.delUser(sysUserDTO.getUserId(), "sys");
        }
        return sysUser.getId();
    }

    /**
     * 查询用户列表
     *
     * @param sysUserListReqDTO
     * @return
     */
    @Override
    public List<SysUserDTO> getUserList(SysUserListReqDTO sysUserListReqDTO) {
        SysUser searchSysUser = new SysUser();
        searchSysUser.setId(sysUserListReqDTO.getUserId());
        searchSysUser.setStatus(sysUserListReqDTO.getStatus());
        if (StringUtils.isNotEmpty(sysUserListReqDTO.getPhoneNumber())) {
            searchSysUser.setPhoneNumber(
                    AESUtil.encryptHex(sysUserListReqDTO.getPhoneNumber()));
        }
        List<SysUser> sysUserList = sysUserMapper.selectList(searchSysUser);
        return sysUserList.stream()
                .map(sysUser -> {
                    SysUserDTO sysUserDTO = new SysUserDTO();
                    sysUserDTO.setUserId(sysUser.getId());
                    sysUserDTO.setPhoneNumber(
                            AESUtil.decryptHex(sysUser.getPhoneNumber()));
                    sysUserDTO.setNickName(sysUser.getNickName());
                    sysUserDTO.setRemark(sysUser.getRemark());
                    sysUserDTO.setIdentity(sysUser.getIdentity());
                    sysUserDTO.setStatus(sysUser.getStatus());
                    return sysUserDTO;
                }).collect(Collectors.toList());
    }

    /**
     * 获取B端用户登录信息
     * @return B端用户信息
     */
    @Override
    public SysUserLoginDTO getLoginUser() {
        // 获取用户登录信息
        LoginUserDTO loginUserDTO = tokenService.getLoginUser();
        if (null == loginUserDTO || null == loginUserDTO.getUserId()) {
            throw new ServiceException("用户令牌有误！", ResultCode.INVALID_PARA.getCode());
        }
        // 查询mysql
        SysUser sysUser = sysUserMapper.selectById(loginUserDTO.getUserId());
        if (null == sysUser) {
            throw new ServiceException("用户不存在！", ResultCode.INVALID_PARA.getCode());
        }
        SysUserLoginDTO sysUserLoginDTO = new SysUserLoginDTO();
        BeanUtils.copyProperties(loginUserDTO, sysUserLoginDTO);
        BeanUtils.copyProperties(sysUser, sysUserLoginDTO);
        return sysUserLoginDTO;
    }

}